#!/usr/bin/env bash
#  Copyright (c) 2017 Shadowfox <bitplease@shadowfox.top>
#
#  Permission to use, copy, modify, and distribute this software for any
#  purpose with or without fee is hereby granted, provided that the above
#  copyright notice and this permission notice appear in all copies.
#
#  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
#  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
#  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
#  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
#  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
#  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
#  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

umask 077

usage() {

	cat <<-EOT
${OGT_VERLN}

usage:  ${OGT_BIN} [ -p tcp|udp ] [ -c CC ] [ -r ]

              -p    download vpns based on protocol
              -c    download vpns from a specific country
              -r    remove vpn files that takes more than 1 second to connect
              -h    show this help
              -v    show version and exit
EOT
}

header() {
	cat <<-EOT
                      _ ._  _ ._  _  _._|_ _
                     |_||_)(/_| |(_|(_| |_(/_
                        |         _|   v${OGT_VER}
EOT
}

error() {

	local err_msg="${1}"
	local err_cmd="${2:=msg}"

	printf "%s\n\n" "${err_msg}" >&2

	if [[ "${err_cmd}" == "usage" ]]; then
		usage >&2
		exit "${OGT_EXT_ERR_USG}"
	fi

	exit "${OGT_EXT_ERR_MSG}"
}

to_lower() {

	printf "%s" "${1}" | tr '[:upper:]' '[:lower:]'
}

to_upper() {

	printf "%s" "${1}" | tr '[:lower:]' '[:upper:]'
}

base64_decode() {

	local B64ENC="${1}"
	local OGTFILE="${2}"

	printf "%s" "${B64ENC}" | base64 -d > "${OGTFILE}"
}

download() {

	local OGT_URL="http://www.vpngate.net/api/iphone/"

	if [[ ! -d "${OGT_DIR}" ]]; then
		mkdir -p "${OGT_DIR}"
	fi

	local OGT_TMP_CSV="$(mktemp -u "${OGT_TMP_DIR}/XXXXXX")"
	header
	printf "%s\n\n" "Downloading list"

	if  [[ "${OGT_DOWNLOAD}" == "curl" ]]; then
		curl -# "${OGT_URL}" -o "${OGT_TMP_CSV}"
	else
		wget -q "${OGT_URL}" -O "${OGT_TMP_CSV}"
	fi

	if [[ "${OGT_CC}" == "all" ]]; then
		sed '1,2d;$d;s/\r//' "${OGT_TMP_CSV}" > "${OGT_FILE}"
	else
		sed -n "s/\r//;/,${OGT_CC},/p" "${OGT_TMP_CSV}" > "${OGT_FILE}"
	fi

	while IFS=, read -r HOST IP SCORE PING SPEED CSTR CC NVS UP USRS TRAFF LOG OWNER MSG B64CFG; do
		local cc=$(to_lower "${CC}")

		if [[ ! -d "${OGT_DIR}/${OGT_PROTO}/${cc}" ]]; then
			mkdir -p "${OGT_DIR}/${OGT_PROTO}/${cc}"
		fi

		local OGT_TMP_FILE="$(mktemp -u "${OGT_TMP_DIR}/XXXXXX")"
		base64_decode "${B64CFG}" "${OGT_TMP_FILE}"

		if grep -qs "^proto ${OGT_PROTO}" "${OGT_TMP_FILE}"; then
			mv "${OGT_TMP_FILE}" "${OGT_DIR}/${OGT_PROTO}/${cc}/${HOST}.ovpn"
			{ printf "Added: %s" "${HOST} ${IP} ${SCORE} ${PING} ${SPEED}";
			printf " %s " "${CSTR} ${CC} ${NVS} ${UP} ${USRS}";
			printf "%s\n" "${TRAFF} ${LOG} ${OWNER} ${MSG}";} >> "${OGT_DIR}/.log"
		fi

	done < "${OGT_FILE}"

	exit "${OGT_EXT_OK}"
}

clean_vpns() {
	if [[ ! -d "${OGT_DIR}/${OGT_PROTO}" ]]; then
		error "ERR: Directory not found"
	else
		if [[ ! $(command -v nc) ]]; then
			error "ERR:  could not find netcat. Make sure to install it" msg
		fi

		find ${OGT_DIR}/${OGT_PROTO}/ -type f |
		while read file; do
			local HOST=$(grep "^remote" <${file} | cut -d " " -f2- | tr -d '\015')
			printf "Checking VPN file: %s\n" ${file}

			if [[ ${OGT_PROTO} == 'tcp' ]]; then
				local NC_OPT="znw"
			else
				local NC_OPT="uznw"
			fi

			if [[ $(nc -${NC_OPT} 1 ${HOST}; echo -n $?) -ne 0 ]]; then
				printf "Deleting VPNG file: %s\n" ${file}
				printf "Deleted: %s\n" "${file}" >> "${OGT_DIR}/.log"
				rm "${file}"
			fi
		done
	fi
}

main() {

	local OGT_VER="0.1.0"
	local OGT_BIN="${0##*\/}"
	local OGT_VERLN="${OGT_BIN} version ${OGT_VER}"

	local OGT_EXT_OK=0
	local OGT_EXT_ERR_MSG=1
	local OGT_EXT_ERR_USG=2

	local OGT_DIR="${HOME}/.config/opengate"
	local OGT_FILE="${OGT_DIR}/.csv_list"

	local OGT_PROTO="udp"
	local OGT_CC="all"
	local OGT_RMDEAD="false"

	local OGT_TMP_DIR="$(mktemp -d "/tmp/ogt.XXXXXXXXXXXX")"
	trap 'rm -rf "${OGT_TMP_DIR}"' INT HUP TERM EXIT

	local OGT_ISO3166_1=( AF AX AL DZ AS AD AO AI AQ AG AR AM AW AU AT AZ BS \
        BH BD BB BY BE BZ BJ BM BT BO BA BW BV BR IO BN BG BF BI KH CM CA CV \
        KY CF TD CL CN CX CC CO KM CG CD CK CR CI HR CU CY CZ DK DJ DM DO EC \
        EG SV GQ ER EE ET FK FO FJ FI FR GF PF TF GA GM GE DE GH GI GR GL GD \
        GP GU GT GG GN GW GY HT HM VA HN HK HU IS IN ID IR IQ IE IM IL IT JM \
        JP JE JO KZ KE KI KR KW KG LA LV LB LS LR LY LI LT LU MO MK MG MW MY \
        MV ML MT MH MQ MR MU YT MX FM MD MC MN ME MS MA MZ MM NA NR NP NL AN \
        NC NZ NI NE NG NU NF MP NO OM PK PW PS PA PG PY PE PH PN PL PT PR QA \
        RE RO RU RW BL SH KN LC MF PM VC WS SM ST SA SN RS SC SL SG SK SI SB \
        SO ZA GS ES LK SD SR SJ SZ SE CH SY TW TJ TZ TH TL TG TK TO TT TN TR \
        TM TC TV UG UA AE GB US UM UY UZ VU VE VN VG VI WF EH YE ZM ZW )

	local OGT_DOWNLOAD=""

	if [[ $(command -v curl) ]]; then
		OGT_DOWNLOAD="curl"
	elif [[ $(command -v wget) ]]; then
		OGT_DOWNLOAD="wget"
	else
		error "ERR: Make sure to install curl or wget" msg
	fi

	while getopts ":hvrp:c:" opt; do
		case $opt in
			p)
				if [[ ${OPTARG} == 'tcp' ]] || [[ ${OPTARG} == 'udp' ]]; then
					OGT_PROTO="${OPTARG}"
				else
					error "ERR: -${OPTARG} is not a valid option." usage
				fi
				;;
			c)
				if OGT_CC="$(to_upper ${OPTARG})" &&
					[[ ! ${OGT_ISO3166_1[@]} =~ "${OGT_CC}" ]]; then
						error "ERR: -${OPTARG} is not a valid option." usage
				fi
				;;
			r)
				OGT_RMDEAD="true"
				;;
			h)
				usage
				exit ${OGT_EXT_OK}
				;;
			v)
				printf "%s\n" "${OGT_VERLN}"
				exit ${OGT_EXT_OK}
				;;
			:)
				error "ERR: -${OPTARG} requires an argument." usage
				;;
			\?)
				error "ERR: -${OPTARG} is not a valid option." usage
				;;
		esac
	done

	if [[ ${OGT_RMDEAD} == "true" ]]; then
		 clean_vpns
	else
		download
	fi
}

main "$@"

